Micron Document
🎖️GitЯра🎖️

Commit 228fa8a368d478a9a244da2eebaef812ae724df5


Parents : f6a3f09
Author : James Rich <2199651+jamesarich@users.noreply.github.com>
Signature : Signature validation error
Date : 2026-07-10T08:31:54-05:00
Committer : GitHub <noreply@github.com>
Date : 2026-07-10T13:31:54Z

fix: dedup node lists to prevent LazyColumn duplicate-key crash (#6193)

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>

Changes
Diff

diff --git a/androidApp/src/google/kotlin/org/meshtastic/app/map/component/ClusterItemsListDialog.kt b/androidApp/src/google/kotlin/org/meshtastic/app/map/component/ClusterItemsListDialog.kt
index d69e3f316b..18226a0bb6 100644
--- a/androidApp/src/google/kotlin/org/meshtastic/app/map/component/ClusterItemsListDialog.kt
+++ b/androidApp/src/google/kotlin/org/meshtastic/app/map/component/ClusterItemsListDialog.kt
@@ -48,7 +48,9 @@ fun ClusterItemsListDialog(
text = {
// Use a LazyColumn for potentially long lists of items
LazyColumn(contentPadding = PaddingValues(vertical = 8.dp)) {
- items(items, key = { it.node.num }) { item ->
+ // Dedup by node.num: it's the LazyColumn key and must be unique, but filteredNodes can
+ // contain the same node from two sources (or a num=0 placeholder). See NodeListScreen.
+ items(items.distinctBy { it.node.num }, key = { it.node.num }) { item ->
ClusterDialogListItem(item = item, onClick = { onItemClick(item) })
}
}

diff --git a/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/list/NodeListScreen.kt b/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/list/NodeListScreen.kt
index 8397df5969..8fee0fa3c4 100644
--- a/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/list/NodeListScreen.kt
+++ b/feature/node/src/commonMain/kotlin/org/meshtastic/feature/node/list/NodeListScreen.kt
@@ -106,7 +106,12 @@ fun NodeListScreen(
val scope = rememberCoroutineScope()
val state by viewModel.nodesUiState.collectAsStateWithLifecycle()
- val nodes by viewModel.nodeList.collectAsStateWithLifecycle()
+ // Dedup by num: it's the LazyColumn key (must be unique) but the upstream flow can momentarily emit
+ // two entries with the same num (a num=0 unknown-node placeholder, or a brief double-emission during
+ // an active-DB switch). Dedup once here so the count in the app bar and the rendered rows agree.
+ // Composite "num_index" keys would also fix the crash but break animateItem() reorder animations.
+ val allNodes by viewModel.nodeList.collectAsStateWithLifecycle()
+ val nodes = remember(allNodes) { allNodes.distinctBy { it.num } }
val ourNode by viewModel.ourNodeInfo.collectAsStateWithLifecycle()
val onlineNodeCount by viewModel.onlineNodeCount.collectAsStateWithLifecycle(0)
val totalNodeCount by viewModel.totalNodeCount.collectAsStateWithLifecycle(0)

Served by rngit 1.5.2 - Generated in 0.04s